package clientejava.inteligencia.algoritmos;

import java.util.ArrayList;
import java.util.Iterator;

import clientejava.inteligencia.Estado;
import clientejava.inteligencia.Movimiento;

public abstract class MiniMax extends Algoritmo {

	private int maximaProfundidad;

	public MiniMax(int maximaProfundidad) {
		this.maximaProfundidad = maximaProfundidad;
	}

	public Movimiento getSiguienteMovimiento(int turno, Estado estado)
			throws Exception {

		Resultado resultado=this.minimax(estado, 0, turno);
		if(resultado!=null && !resultado.camino.isEmpty())
			return resultado.camino.get(resultado.camino.size()-1);
		else
			return null;
	}

	private Resultado minimax(Estado estado, int profundidad, int turno) {
		Resultado resultado = new Resultado();
		int valor = this.heuristica(estado, turno);
		if (profundidad == maximaProfundidad || valor == Integer.MAX_VALUE
				|| valor == Integer.MIN_VALUE) {
			resultado.valor = valor;
			return resultado;
		} else {
			ArrayList<Movimiento> sucesores = this.generaMovimientosSucesores(
					estado, turno);
			if (sucesores.isEmpty()) {
				resultado.valor = valor;
				return resultado;
			} else {
				resultado.valor = Integer.MIN_VALUE;
				for (Iterator<Movimiento> iterador = sucesores.iterator(); iterador
						.hasNext();) {
					Estado estadoSucesor = estado.clone();
					Movimiento sucesor = iterador.next();
					try {
						estadoSucesor.aplicaMovimiento(turno, sucesor);

						Resultado resultadoSucesor = this
								.minimax(estadoSucesor, profundidad + 1,
										(turno + 1) % 2);
						if (resultado.valor < -resultadoSucesor.valor) {
							resultado.valor = -resultadoSucesor.valor;
							for (Iterator<Movimiento> iterador2 = resultadoSucesor.camino
									.iterator(); iterador2.hasNext();)
								resultado.camino.add(iterador2.next());

							resultado.camino.add(sucesor);
						}

					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				return resultado;
			}
		}
	}

	protected abstract ArrayList<Movimiento> generaMovimientosSucesores(
			Estado estado, int turno);

	protected abstract int heuristica(Estado estado, int turno);

	class Resultado {
		public int valor;
		public ArrayList<Movimiento> camino = new ArrayList<Movimiento>();
	}
}
